﻿using System.IO;
using UnityEngine;
using UnityEditor;
using JinndevEditor;

namespace Jinndev.Tile2D {

    public class AtlasTool1 : EditorWindow {

        [MenuItem(CommonEditorConst.EditorMenu + "/碎图打图集")]
        public static void ShowWindow() {
            AtlasTool1 window = GetWindow<AtlasTool1>(false);
            window.titleContent = new GUIContent("碎图打图集");
            window.Show();
        }

        private Texture2D[,] textures;
        private Sprite[,] sprites;

        private int _row = 2;
        private int _col = 2;
        private int row = 2;
        private int col = 2;

        private string[] sizeOptions = new string[] { "16", "32", "64", "128", "256", "512" };
        private int[] sizeValues = new int[] { 16, 32, 64, 128, 256, 512 };
        private int unitWidth = 32;
        private int unitHeight = 32;
        private string saveName = "Atlas";

        private void OnGUI() {
            GUILayout.Space(10);

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("图集长宽:", GUILayout.Width(50));
            _col = EditorGUILayout.IntField(_col, GUILayout.Width(40));
            EditorGUILayout.LabelField("x", GUILayout.Width(10));
            _row = EditorGUILayout.IntField(_row, GUILayout.Width(40));
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(5);

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("使用Texture2D创建", GUILayout.Width(160)) && _row > 0 && _col > 0) {
                sprites = null;
                row = _row;
                col = _col;
                textures = new Texture2D[col, row];
            }
            if (GUILayout.Button("使用Sprite创建", GUILayout.Width(160)) && _row > 0 && _col > 0) {
                textures = null;
                row = _row;
                col = _col;
                sprites = new Sprite[col, row];
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(10);

            if (textures != null) {
                for (int y = row - 1; y >= 0; y--) {
                    EditorGUILayout.BeginHorizontal();
                    for (int x = 0; x < col; x++) {
                        textures[x, y] = EditorGUILayout.ObjectField(textures[x, y], typeof(Texture2D), true, GUILayout.Width(80), GUILayout.Height(80)) as Texture2D;
                    }
                    EditorGUILayout.EndHorizontal();
                }
            }
            else if (sprites != null) {
                for (int y = row - 1; y >= 0; y--) {
                    EditorGUILayout.BeginHorizontal();
                    for (int x = 0; x < col; x++) {
                        sprites[x, y] = EditorGUILayout.ObjectField(sprites[x, y], typeof(Sprite), true, GUILayout.Width(80), GUILayout.Height(80)) as Sprite;
                    }
                    EditorGUILayout.EndHorizontal();
                }
            }

            GUILayout.Space(10);

            if (textures != null || sprites != null) {
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("单元大小:", GUILayout.Width(50));
                unitWidth = EditorGUILayout.IntPopup(unitWidth, sizeOptions, sizeValues, GUILayout.Width(60));
                EditorGUILayout.LabelField("x:", GUILayout.Width(10));
                unitHeight = EditorGUILayout.IntPopup(unitHeight, sizeOptions, sizeValues, GUILayout.Width(60));
                EditorGUILayout.EndHorizontal();
                GUILayout.Space(5);

                EditorGUILayout.LabelField("输出文件名:", GUILayout.Width(50));
                saveName = EditorGUILayout.TextField(saveName, GUILayout.Width(240));
                GUILayout.Space(5);

                if (GUILayout.Button("保存", GUILayout.Width(115))) {
                    Save();
                }
            }

            GUILayout.Space(10);
        }

        private void Save() {
            Texture2D output = new Texture2D(unitWidth * col, unitHeight * row);

            for (int y = 0; y < row; y++) {
                for (int x = 0; x < col; x++) {
                    int offsetX = unitWidth * x;
                    int offsetY = unitHeight * y;
                    if (textures != null) {
                        bool readable = SetReadable(textures[x, y], true);
                        CopyColor(textures[x, y], output, offsetX, offsetY);
                        SetReadable(textures[x, y], readable);
                    }
                    else if (sprites != null) {
                        bool readable = SetReadable(sprites[x, y], true);
                        CopyColor(sprites[x, y], output, offsetX, offsetY);
                        SetReadable(sprites[x, y], readable);
                    }
                }
            }
            output.Apply();
            byte[] bytes = output.EncodeToPNG();
            saveName = string.IsNullOrWhiteSpace(saveName) ? "Atlas" : saveName;
            string path = Path.Combine(Application.dataPath, saveName + ".png");
            bool exist = File.Exists(path);
            File.WriteAllBytes(path, bytes);
            AssetDatabase.Refresh();

            output = AssetDatabase.LoadAssetAtPath<Texture2D>($"Assets/{saveName}.png");
            if (!exist) {
                InitOutput(output);
            }
            //Selection.activeObject = output;
        }

        private bool SetReadable(Object obj, bool readable) {
            if (obj == null) {
                return false;
            }
            TextureImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(obj)) as TextureImporter;
            bool isReadable = importer.isReadable;
            if (importer.isReadable != readable) {
                importer.isReadable = readable;
                importer.SaveAndReimport();
            }
            return isReadable;
        }

        private void InitOutput(Texture2D texture) {
            TextureImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;
            importer.alphaIsTransparency = true;
            importer.mipmapEnabled = false;
            importer.SaveAndReimport();
        }

        private void CopyColor(Texture2D input, Texture2D output, int offsetX, int offsetY) {
            int maxX = unitWidth;
            int maxY = unitHeight;
            if (input != null) {
                maxX = Mathf.Min(input.width, maxX);
                maxY = Mathf.Min(input.height, maxY);
            }

            for (int y = 0; y < unitHeight; y++) {
                for (int x = 0; x < unitWidth; x++) {
                    if (input != null && x < maxX && y < maxY) {
                        Color color = input.GetPixel(x, y);
                        output.SetPixel(offsetX + x, offsetY + y, color);
                    }
                    else {
                        output.SetPixel(offsetX + x, offsetY + y, new Color(0, 0, 0, 0));
                    }
                }
            }
        }

        private void CopyColor(Sprite input, Texture2D output, int offsetX, int offsetY) {
            int maxX = unitWidth;
            int maxY = unitHeight;
            Texture2D texture = null;
            int inputOffsetX = 0;
            int inputOffsetY = 0;
            if (input != null) {
                texture = input.texture;
                inputOffsetX = (int)input.textureRect.x;
                inputOffsetY = (int)input.textureRect.y;
                maxX = Mathf.Min((int)input.textureRect.size.x, maxX);
                maxY = Mathf.Min((int)input.textureRect.size.y, maxY);

                var colors = texture.GetPixels(inputOffsetX, inputOffsetY, maxX, maxY);
                output.SetPixels(offsetX, offsetY, maxX, maxY, colors);
            }
            //for (int y = 0; y < size; y++) {
            //    for (int x = 0; x < size; x++) {
            //        if (texture != null && x < maxX && y < maxY) {
            //            Color color = texture.GetPixel(inputOffsetX + x, inputOffsetY + y);
            //            output.SetPixel(offsetX + x, offsetY + y, color);
            //        }
            //        else {
            //            output.SetPixel(offsetX + x, offsetY + y, new Color(0, 0, 0, 0));
            //        }
            //    }
            //}
        }

        //private void Destroy(Object[,] array) {
        //    if (array != null) {
        //        foreach(Object o in array) {
        //            Destroy(o);
        //        }
        //    }
        //}

    }

}